using System;
using System.Collections.Generic;

namespace EstimationStudio.Core
{
	/// <summary>
	///  The <see cref="Estimate"/> class holds estimate related information including project phase, features, and adjustment factors.
	/// </summary>
	[Serializable]
	public class Estimate
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="Estimate"/> class.
		/// </summary>
		public Estimate () 
        {
            ProjectPhase = new ProjectPhase();
            Features = new List<Feature>();
            AdjustmentFactors = new List<AdjustmentFactor>();
        }

		/// <summary>
		/// Gets or sets the estimate id.
		/// </summary>
		/// <value>The estimate id.</value>
        public String EstimateId { get; set; }

		/// <summary>
		/// Gets or sets the estimate date.
		/// </summary>
		/// <value>The estimate date.</value>
        public DateTime DateEstimated { get; set; }

		/// <summary>
		///  Gets or Sets the name of this <see cref="Estimate"/>.
		/// </summary>
        public String Title { get; set; }

		/// <summary>
		///  Gets or Sets the description of this <see cref="Estimate"/>.
		/// </summary>
        public String ProblemDescription { get; set; }

		/// <summary>
		///  Gets or Sets the solution related notes of this <see cref="Estimate"/>.
		/// </summary>
        public String SolutionNotes { get; set; }

		/// <summary>
		///  Gets the current phase of this <see cref="Estimate"/>.
		/// </summary>
        public ProjectPhase ProjectPhase { get; set; }

		/// <summary>
		///  Gets the features assigned to this <see cref="Estimate"/>.
		/// </summary>
        public IList<Feature> Features { get; set; }

		/// <summary>
		///  Gets the adjustment factors assigned to this <see cref="Estimate"/>.
		/// </summary>
        public IList<AdjustmentFactor> AdjustmentFactors { get; set; }

		/// <summary>
		///  Gets the calculated best case for all <see cref="Features"/> in this <see cref="Estimate"/>.
		/// </summary>
		public EstimateRange BestCase
		{
			get
			{
				EstimateRange bestCase = new EstimateRange();
                if (ProjectPhase == null)
                    return bestCase;

				foreach (Feature feature in Features)
					bestCase.Nominal += feature.BestCase;

				foreach (AdjustmentFactor adjustmentFactor in AdjustmentFactors)
					bestCase.Nominal *= adjustmentFactor.Value;

				bestCase.Low = bestCase.Nominal * ProjectPhase.ErrorVariability.Low;
				bestCase.High = bestCase.Nominal * ProjectPhase.ErrorVariability.High;

				return bestCase;
			}
		}

		/// <summary>
		///  Gets the calculated expected case for all <see cref="Features"/> in this <see cref="Estimate"/>.
		/// </summary>
		public EstimateRange ExpectedCase
		{
			get
			{
				EstimateRange expectedCase = new EstimateRange();
                if (ProjectPhase == null)
                    return expectedCase;

				foreach (Feature feature in Features)
					expectedCase.Nominal += feature.ExpectedCase;

				foreach (AdjustmentFactor adjustmentFactor in AdjustmentFactors)
					expectedCase.Nominal *= adjustmentFactor.Value;

				expectedCase.Low = expectedCase.Nominal * ProjectPhase.ErrorVariability.Low;
				expectedCase.High = expectedCase.Nominal * ProjectPhase.ErrorVariability.High;

				return expectedCase;
			}
		}

		/// <summary>
		///  Gets the calculated worst case for all <see cref="Features"/> in this <see cref="Estimate"/>.
		/// </summary>
		public EstimateRange WorstCase
		{
			get
			{
				EstimateRange worstCase = new EstimateRange();
                if (ProjectPhase == null)
                    return worstCase;

				foreach (Feature feature in Features)
					worstCase.Nominal += feature.WorstCase;

				foreach (AdjustmentFactor adjustmentFactor in AdjustmentFactors)
					worstCase.Nominal *= adjustmentFactor.Value;

				worstCase.Low = worstCase.Nominal * ProjectPhase.ErrorVariability.Low;
				worstCase.High = worstCase.Nominal * ProjectPhase.ErrorVariability.High;

				return worstCase;
			}
		}
	}
}